--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Node / ReticulumProjects / MeshChatX.git / files / vendor / rns_over_http / tests / test_http2_http3.py
Displaying Raw • Download
vendor/rns_over_http/tests/test_http2_http3.py HEAD (2bf00cb3) Text, 8.99 KB
T8b949e"""HTTP/2 and HTTP/3 tunnel tests over TLS."""
Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations
Tff7b72import T7ee787io
Tff7b72import T7ee787socket
Tff7b72import T7ee787time
Tff7b72import T7ee787httpx
Tff7b72import T7ee787pytest
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj
Tff7b72import T7ee787HTTPInterface Tff7b72as T7ee787http_mod
Tff7b72from T7ee787HTTPInterface Tff7b72import Te6edf3HDLCTb4b4b4, Te6edf3HTTPTunnelInterface
Tff7b72from T7ee787testsT7ee787.T7ee787tls_certs Tff7b72import Te6edf3write_self_signed_cert
Tff7b72def Td2a8fffree_tcp_portTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3socketTff7b72.Td2a8ffsocketTb4b4b4(Te6edf3socketTff7b72.Td2a8ffAF_INETTb4b4b4, Te6edf3socketTff7b72.Td2a8ffSOCK_STREAMTb4b4b4) Tff7b72as Te6edf3sTb4b4b4:
Te6edf3sTff7b72.Td2a8ffbindTb4b4b4(Tb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Tff7b72return Te6edf3sTff7b72.Td2a8ffgetsocknameTb4b4b4(Tb4b4b4)Tb4b4b4[T79c0ff1Tb4b4b4]
Tff7b72def Td2a8ffwait_tcp_openTb4b4b4(Te6edf3hostTb4b4b4, Te6edf3portTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4)Tb4b4b4:
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeout
Tff7b72while Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72with Te6edf3socketTff7b72.Td2a8ffcreate_connectionTb4b4b4(Tb4b4b4(Te6edf3hostTb4b4b4, Te6edf3portTb4b4b4)Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff0.3Tb4b4b4)Tb4b4b4:
Tff7b72return
Tff7b72except Tf85149OSErrorTb4b4b4:
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.05Tb4b4b4)
Te6edf3pytestTff7b72.Td2a8fffailTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffport Tffd700{Te6edf3hostTffd700}Ta5d6ff:Tffd700{Te6edf3portTffd700}Ta5d6ff did not open within Tffd700{Te6edf3timeoutTffd700}Ta5d6ffsTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffwait_udp_boundTb4b4b4(Te6edf3hostTb4b4b4, Te6edf3portTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4)Tb4b4b4:
T8b949e"""Best-effort wait until something is listening on UDP port."""
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeout
Tff7b72while Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4:
T8b949e# Hypercorn QUIC bind is harder to probe; give the ASGI thread time.
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
T8b949e# Also accept TCP (Hypercorn binds TCP even for HTTP/3 mode).
Tff7b72tryTb4b4b4:
Tff7b72with Te6edf3socketTff7b72.Td2a8ffcreate_connectionTb4b4b4(Tb4b4b4(Te6edf3hostTb4b4b4, Te6edf3portTb4b4b4)Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff0.2Tb4b4b4)Tb4b4b4:
Tff7b72return
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72continue
Te6edf3pytestTff7b72.Td2a8fffailTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffHTTP/3 server did not become ready on Tffd700{Te6edf3hostTffd700}Ta5d6ff:Tffd700{Te6edf3portTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffconfigobj_from_linesTb4b4b4(Te6edf3linesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3ConfigObjTb4b4b4(Te6edf3ioTff7b72.Td2a8ffStringIOTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3linesTb4b4b4) Tff7b72+ Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72class T56d364RecordingOwnerTb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpackets Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffinboundTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3dataTb4b4b4, Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpacketsTff7b72.Td2a8ffappendTb4b4b4(Tffa657bytesTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4)
Tff7b72def Td2a8fflast_payloadTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff10.0Tb4b4b4, Te6edf3pollTff7b72=T79c0ff0.05Tb4b4b4)Tb4b4b4:
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeout
Tff7b72while Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffpacketsTb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffpacketsTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(Te6edf3pollTb4b4b4)
Tff7b72return Tff7b72None
Tff7b72def Td2a8ffwait_countTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3nTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4)Tb4b4b4:
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeout
Tff7b72while Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpacketsTb4b4b4) Tff7b72>Tff7b72= Te6edf3nTb4b4b4:
Tff7b72return Tffa657listTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpacketsTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.05Tb4b4b4)
Tff7b72return Tff7b72None
Tff7b72def Td2a8ffmake_tls_pairTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4, Te6edf3http_versionTb4b4b4, Te6edf3poll_intervalTff7b72=T79c0ff0.05Tb4b4b4)Tb4b4b4:
Te6edf3certTb4b4b4, Te6edf3key Tff7b72= Te6edf3write_self_signed_certTb4b4b4(Te6edf3tmp_path Tff7b72/ Ta5d6fffTa5d6ff"Ta5d6ffcerts-hTffd700{Te6edf3http_versionTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3owner_s Tff7b72= Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)
Te6edf3owner_c Tff7b72= Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)
Te6edf3server Tff7b72= Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3owner_sTb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = srvTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = serverTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflisten_host = 127.0.0.1Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fflisten_port = Tffd700{Te6edf3free_portTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffhttp_version = Tffd700{Te6edf3http_versionTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fftls_certfile = Tffd700{Te6edf3certTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fftls_keyfile = Tffd700{Te6edf3keyTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffpoll_interval = Tffd700{Te6edf3poll_intervalTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3http_version Tff7b72== T79c0ff3Tb4b4b4:
Te6edf3wait_udp_boundTb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4, Te6edf3free_portTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3wait_tcp_openTb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4, Te6edf3free_portTb4b4b4)
T8b949e# Extra settle time for Hypercorn TLS/QUIC startup
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.3Tb4b4b4)
Te6edf3url Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ffhttps://127.0.0.1:Tffd700{Te6edf3free_portTffd700}Ta5d6ff/Ta5d6ff"
Te6edf3client Tff7b72= Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3owner_cTb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = cliTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = clientTa5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffserver_url = Tffd700{Te6edf3urlTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffhttp_version = Tffd700{Te6edf3http_versionTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fftls_verify = falseTa5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffpoll_interval = Tffd700{Te6edf3poll_intervalTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3owner_sTb4b4b4, Te6edf3owner_cTb4b4b4, Te6edf3serverTb4b4b4, Te6edf3client
Tf0883e@pytestTff7b72.Td2a8fffixture
Tff7b72def Td2a8fffree_portTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3free_tcp_portTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_http2_requires_tls_on_serverTb4b4b4(Te6edf3free_portTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6fftls_certfileTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = srvTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = serverTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflisten_host = 127.0.0.1Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fflisten_port = Tffd700{Te6edf3free_portTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffhttp_version = 2Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8fftest_http3_client_requires_https_urlTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffhttps://Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = cliTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = clientTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffserver_url = http://127.0.0.1:9/Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffhttp_version = 3Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8fftest_invalid_http_version_rejectedTb4b4b4(Te6edf3free_portTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffhttp_versionTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = srvTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = serverTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflisten_host = 127.0.0.1Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fflisten_port = Tffd700{Te6edf3free_portTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffhttp_version = 4Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8fftest_http2_bidirectional_tunnelTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4)Tb4b4b4:
Te6edf3owner_sTb4b4b4, Te6edf3owner_cTb4b4b4, Te6edf3serverTb4b4b4, Te6edf3client Tff7b72= Te6edf3make_tls_pairTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4, T79c0ff2Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6ffbTa5d6ff"Ta5d6ffh2-clientTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3owner_sTff7b72.Td2a8fflast_payloadTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4) Tff7b72== Ta5d6ffbTa5d6ff"Ta5d6ffh2-clientTa5d6ff"
Te6edf3serverTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6ffbTa5d6ff"Ta5d6ffh2-serverTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3owner_cTff7b72.Td2a8fflast_payloadTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4) Tff7b72== Ta5d6ffbTa5d6ff"Ta5d6ffh2-serverTa5d6ff"
T8b949e# Confirm httpx negotiated HTTP/2
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72+ T79c0ff5.0
Tff7b72while Te6edf3timeTff7b72.Td2a8ffmonotonicTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4:
Tff7b72if Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflast_http_versionTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffHTTP/2Ta5d6ff"Tb4b4b4:
Tff7b72break
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.05Tb4b4b4)
Tff7b72assert Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6fflast_http_versionTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffHTTP/2Ta5d6ff"
Tff7b72assert Te6edf3serverTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffhttp_requestsTa5d6ff"Tb4b4b4] Tff7b72>Tff7b72= T79c0ff1
Tff7b72finallyTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Te6edf3serverTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_http2_reuses_connection_across_pollsTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4)Tb4b4b4:
Te6edf3owner_sTb4b4b4, Te6edf3owner_cTb4b4b4, Te6edf3serverTb4b4b4, Te6edf3client Tff7b72= Te6edf3make_tls_pairTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4, T79c0ff2Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff6Tb4b4b4)Tb4b4b4:
Te6edf3clientTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffh2p-Tffd700{Te6edf3iTffd700}Ta5d6ff"Tff7b72.Td2a8ffencodeTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3payloads Tff7b72= Te6edf3owner_sTff7b72.Td2a8ffwait_countTb4b4b4(T79c0ff6Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff20.0Tb4b4b4)
Tff7b72assert Te6edf3payloads Tff7b72is Tff7b72not Tff7b72None
Tff7b72assert Te6edf3payloadsTb4b4b4[Tff7b72-T79c0ff6Tb4b4b4:Tb4b4b4] Tff7b72== Tb4b4b4[Ta5d6fffTa5d6ff"Ta5d6ffh2p-Tffd700{Te6edf3iTffd700}Ta5d6ff"Tff7b72.Td2a8ffencodeTb4b4b4(Tb4b4b4) Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff6Tb4b4b4)Tb4b4b4]
Te6edf3stats Tff7b72= Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)
T8b949e# Packets may be batched into fewer HTTP exchanges on one h2 connection
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffclient_requestsTa5d6ff"Tb4b4b4] Tff7b72>Tff7b72= T79c0ff1
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffclient_requestsTa5d6ff"Tb4b4b4] Tff7b72<Tff7b72= T79c0ff6
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6fflast_http_versionTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffHTTP/2Ta5d6ff"
Tff7b72finallyTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Te6edf3serverTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_http2_external_client_sees_h2Tb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4)Tb4b4b4:
Te6edf3certTb4b4b4, Te6edf3key Tff7b72= Te6edf3write_self_signed_certTb4b4b4(Te6edf3tmp_path Tff7b72/ Ta5d6ff"Ta5d6ffcerts-extTa5d6ff"Tb4b4b4)
Te6edf3server Tff7b72= Te6edf3HTTPTunnelInterfaceTb4b4b4(
Te6edf3RecordingOwnerTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3configobj_from_linesTb4b4b4(
Tb4b4b4[
Ta5d6ff"Ta5d6ffname = srvTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode = serverTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflisten_host = 127.0.0.1Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fflisten_port = Tffd700{Te6edf3free_portTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffhttp_version = 2Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fftls_certfile = Tffd700{Te6edf3certTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6fftls_keyfile = Tffd700{Te6edf3keyTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3wait_tcp_openTb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4, Te6edf3free_portTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.3Tb4b4b4)
Tff7b72with Te6edf3httpxTff7b72.Td2a8ffClientTb4b4b4(Te6edf3http2Tff7b72=Tff7b72TrueTb4b4b4, Te6edf3verifyTff7b72=Tff7b72FalseTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff5.0Tb4b4b4) Tff7b72as Te6edf3cTb4b4b4:
Te6edf3r Tff7b72= Te6edf3cTff7b72.Td2a8ffpostTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffhttps://127.0.0.1:Tffd700{Te6edf3free_portTffd700}Ta5d6ff/Ta5d6ff"Tb4b4b4,
Te6edf3contentTff7b72=Te6edf3HDLCTff7b72.Td2a8ffframeTb4b4b4(Ta5d6ffbTa5d6ff"Ta5d6ffext-h2Ta5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffUser-AgentTa5d6ff"Tb4b4b4: Te6edf3HTTPTunnelInterfaceTff7b72.Td2a8ffTUNNEL_USER_AGENTTb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72assert Te6edf3rTff7b72.Td2a8ffstatus_code Tff7b72== T79c0ff200
Tff7b72assert Te6edf3rTff7b72.Td2a8ffhttp_version Tff7b72== Ta5d6ff"Ta5d6ffHTTP/2Ta5d6ff"
Tff7b72finallyTb4b4b4:
Te6edf3serverTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_http3_bidirectional_tunnelTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4)Tb4b4b4:
Te6edf3owner_sTb4b4b4, Te6edf3owner_cTb4b4b4, Te6edf3serverTb4b4b4, Te6edf3client Tff7b72= Te6edf3make_tls_pairTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4, T79c0ff3Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6ffbTa5d6ff"Ta5d6ffh3-clientTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3owner_sTff7b72.Td2a8fflast_payloadTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff20.0Tb4b4b4) Tff7b72== Ta5d6ffbTa5d6ff"Ta5d6ffh3-clientTa5d6ff"
Te6edf3serverTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6ffbTa5d6ff"Ta5d6ffh3-serverTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3owner_cTff7b72.Td2a8fflast_payloadTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff20.0Tb4b4b4) Tff7b72== Ta5d6ffbTa5d6ff"Ta5d6ffh3-serverTa5d6ff"
Tff7b72assert Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6fflast_http_versionTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffHTTP/3Ta5d6ff"
Tff7b72assert Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffclient_requestsTa5d6ff"Tb4b4b4] Tff7b72>Tff7b72= T79c0ff1
Tff7b72assert Te6edf3serverTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffhttp_requestsTa5d6ff"Tb4b4b4] Tff7b72>Tff7b72= T79c0ff1
Tff7b72finallyTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Te6edf3serverTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_http3_persistent_session_multiple_postsTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4)Tb4b4b4:
Te6edf3owner_sTb4b4b4, Te6edf3owner_cTb4b4b4, Te6edf3serverTb4b4b4, Te6edf3client Tff7b72= Te6edf3make_tls_pairTb4b4b4(Te6edf3tmp_pathTb4b4b4, Te6edf3free_portTb4b4b4, T79c0ff3Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4:
Te6edf3clientTff7b72.Td2a8ffprocess_outgoingTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffh3p-Tffd700{Te6edf3iTffd700}Ta5d6ff"Tff7b72.Td2a8ffencodeTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3payloads Tff7b72= Te6edf3owner_sTff7b72.Td2a8ffwait_countTb4b4b4(T79c0ff5Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff25.0Tb4b4b4)
Tff7b72assert Te6edf3payloads Tff7b72is Tff7b72not Tff7b72None
Tff7b72assert Te6edf3payloadsTb4b4b4[Tff7b72-T79c0ff5Tb4b4b4:Tb4b4b4] Tff7b72== Tb4b4b4[Ta5d6fffTa5d6ff"Ta5d6ffh3p-Tffd700{Te6edf3iTffd700}Ta5d6ff"Tff7b72.Td2a8ffencodeTb4b4b4(Tb4b4b4) Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4]
Te6edf3stats Tff7b72= Te6edf3clientTff7b72.Td2a8ffconnection_statsTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffpool_num_connectionsTa5d6ff"Tb4b4b4] Tff7b72== T79c0ff1
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffpool_num_requestsTa5d6ff"Tb4b4b4] Tff7b72>Tff7b72= T79c0ff1
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffpool_num_requestsTa5d6ff"Tb4b4b4] Tff7b72<Tff7b72= T79c0ff5
Tff7b72assert Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6fflast_http_versionTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffHTTP/3Ta5d6ff"
Tff7b72finallyTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Te6edf3serverTff7b72.Td2a8ffdetachTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8fftest_module_still_exports_interface_classTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72assert Te6edf3http_modTff7b72.Td2a8ffinterface_class Tff7b72is Te6edf3HTTPTunnelInterface
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────